package org.dromara.common.mongo.utils;

import org.springframework.data.mongodb.core.query.Update;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * mongodb更改封装
 * @@author starts
 * @Date: 2023/4/4 9:32
 * <a href="https://blog.csdn.net/qq_41853447/article/details/115254299">工具来来源 逍遥客.</a>
 */
public class ObjectDisposal {

    /***
     * 将对象中非空的数据转为Update条件，用于MongoDB更改使用
     * @param obj
     * @param <T>
     * @return
     * @throws Exception
     */
    public static Update update(Object obj) {
        try {
            Update update = update(obj, false);
            if (update.getUpdateObject().isEmpty()){
                throw new RuntimeException("暂无更改内容");
            }
            return update;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null ;
    }

    /**
     * 将对象中非空的数据转为Update条件，用于MongoDB更改使用
     * @param t 有数据的那个对象
     * @param cla 当前对象的类型
     * @param considerThread true:考虑现成安全，false：不考虑
     * @param <T>
     * @return
     * @throws Exception
     */
    public static Update update(Object obj, Boolean considerThread) throws ClassNotFoundException {
        Class<?> clazz = null;
        if (considerThread) {
            //通过类装载器获取t类对象
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            clazz = loader.loadClass(obj.getClass().getName());
        } else {
            clazz = obj.getClass();
        }
        Update update = new Update();
        // 获取对象的所有属性
        Field[] fields = clazz.getDeclaredFields();
        // 获取对象所有方法
        Method[] methods = clazz.getMethods();

        // TODO: 2021/3/26 方法二
        Arrays.stream(fields).forEach(field -> {
            // 属性名
            String fieldName = field.getName();
            // 这个属性不用管，是实现序列化时定义的属性。
            if ("serialVersionUID".equals(fieldName)) {
                return;
            }
            Arrays.stream(methods).forEach(method -> {
                if (("get" + fieldName).toLowerCase().equals(method.getName().toLowerCase())) {
                    try {
                        // 这里就可以获取到数据了。
                        Object invoke = method.invoke(obj);
                        if (!ObjectUtils.isEmpty(invoke)) {
                            update.set(fieldName, invoke);
                        }
                    } catch (IllegalAccessException e) {
                    } catch (InvocationTargetException e) {
                    }
                }
            });
        });
        return update;
    }

    /**
     * 将对象中中的数据转为Update条件，用于MongoDB更改使用。这个方法不排除空数据，即使是空数据多添加到条件中。
     * @param obj
     * @param <T>
     * @return
     * @throws Exception
     */
    public static<T> Update updateOfNull(Object obj) throws Exception {
        return updateOfNull(obj,false);
    }

    /**
     * 将对象中中的数据转为Update条件，用于MongoDB更改使用。这个方法不排除空数据，即使是空数据多添加到条件中。
     * @param t 有数据的那个对象
     * @param cla 当前对象的类型
     * @param considerThread true:考虑现成安全，false：不考虑
     * @param <T>
     * @return
     * @throws Exception
     */
    public static<T> Update updateOfNull(Object obj, Boolean considerThread) throws Exception {
        Class<?> clazz = null;
        if (considerThread) {
            //通过类装载器获取t类对象
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            clazz = loader.loadClass(obj.getClass().getName());
        } else {
            clazz = obj.getClass();
        }
        Update update = new Update();
        // 获取对象的所有属性
        Field[] fields = clazz.getDeclaredFields();
        // 获取对象所有方法
        Method[] methods = clazz.getMethods();

        // TODO: 2021/3/26 方法二
        // TODO: 2021/3/26 方法二
        Arrays.stream(fields).forEach(field -> {
            // 属性名
            String fieldName = field.getName();
            Arrays.stream(methods).forEach(method -> {
                if (("get" + fieldName).toLowerCase().equals(method.getName().toLowerCase())) {
                    try {
                        // 这里就可以获取到数据了。
                        Object invoke = method.invoke(obj);
                        if (!ObjectUtils.isEmpty(invoke)) {
                            update.set(fieldName, invoke);
                        }
                    } catch (IllegalAccessException e) {
                    } catch (InvocationTargetException e) {
                    }
                }
            });
        });
        return update;
    }

}
